package com.imflea.zero.config;

import com.imflea.zero.anno.NoRepeatSubmit;
import com.imflea.zero.exception.BizException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.types.Expiration;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @author zhaoyang
 * @version 1.0
 * @project farmplus-service
 * @package com.imflea.zero.config
 * @filename 创建时间: 2021/11/1
 * @description 参考博客 https://www.cnblogs.com/chengxy-nds/p/12267090.html
 * @copyright Copyright (c) 2021 中国软件与技术服务股份有限公司
 */
@Aspect
@Configuration
public class LockMethodInterceptor {


    private final StringRedisTemplate stringRedisTemplate;

    @Autowired
    public LockMethodInterceptor(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }


    @Around("execution(public * * (..)) && @annotation(com.imflea.zero.anno.NoRepeatSubmit)")
    public Object interceptor(ProceedingJoinPoint joinPoint) throws Throwable {

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();

        NoRepeatSubmit cacheLock = method.getAnnotation(NoRepeatSubmit.class);
        String key = getKey(cacheLock.key(), joinPoint.getArgs());
        final Boolean success = stringRedisTemplate.execute(
                (RedisCallback<Boolean>) connection -> connection.set(key.getBytes(), new byte[0], Expiration.from(cacheLock.expire(), TimeUnit.SECONDS)
                        , RedisStringCommands.SetOption.SET_IF_ABSENT));
        if (!success) {
            // TODO 按理来说 我们应该抛出一个自定义的 CacheLockException 异常;这里偷下懒
            throw new BizException("请勿重复请求");
        }

        return joinPoint.proceed();
    }


    private String getKey(String keyExpress, Object[] args) {
        for (int i = 0; i < args.length; i++) {
            keyExpress = keyExpress.replace("arg[" + i + "]", args[i].toString());
        }
        return keyExpress;
    }
}
